// 函数指针
// 我们可以把一个闭包传给一个函数作为参数, 同时一个函数作为参数传给另一个函数
// 函数在传递过程中会被转换为fn类型, 这里所谓的fn类型就是函数指针
fn main() {
    // 1. 基本使用
   fn add_one(a: i32) -> i32 {
    a + 1
   }

   fn add_twice(f: fn(i32) -> i32, args: i32) -> i32 {
        f(args) + f(args)
   }

   let res = add_twice(add_one, 2);
   println!("the result: {}", res);

//    2. 和闭包
//    函数指针实现了三种trait(Fn, FnOnce, FnMut), 所以, 一个接受闭包的函数, 也能接受一个函数作为参数
   let list_of_numbers = vec![1,2,3,4,5];
   let list_of_strings: Vec<String> = list_of_numbers.iter().map(|x| x.to_string()).collect();
    //    也可以写成:
    // let list_of_strings: Vec<String> = list_of_numbers.iter().map(ToString::to_string).collect();

    println!("list_of_string:{:?}", list_of_strings);

    // 3. 枚举形式的函数指针
    #[derive(Debug)]
    enum Status {
        Value(u32),
        Stop,
    }
    // Status::Value也是一个实现了闭包trait的函数指针
    // Status::Value相当于是一个枚举函数, 它符合map对函数的需求
    let list_of_status:Vec<Status> = (0u32..5).map(Status::Value).collect();
    println!("list_of_status:{:?}", list_of_status);

    // 4.无法在一个函数中返回闭包, 但是可以返回一个实现了闭包的类型
    // 此时rust无法知道其返回的值的大小
    // fn returns_closures() -> Fn(i32) -> i32 {
    //     |x| x + 1
    // }
    // 所以可以使用Box
    fn returns_closures() -> Box<dyn Fn(i32) -> i32> {
        Box::new(|x| x + 1)
    }
    let closure_fn = returns_closures();
    let closure_result = closure_fn(12);
    println!("closure_result:{}", closure_result);

}
